package com.seal.tsms.base.dao;

import com.seal.tsms.base.log.BaseLog;
import org.hibernate.*;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.transform.ResultTransformer;
import org.hibernate.transform.Transformers;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * Created by seal.jing on 2015/12/22.
 */
public abstract class AbstractBaseDao<E extends Serializable,PK extends Serializable> extends BaseLog implements BaseDao<E,PK>{
    @Autowired
    private SessionFactory sessionFactory;
    protected Class type;

    public Class getType() {
        return type;
    }

    public void setType(Class type) {
        this.type = type;
    }

    public Session getSession() {
        return sessionFactory.getCurrentSession();
    }

    public Criteria getCriteria() {
        return getSession().createCriteria(type);
    }

    public Query getQuery(String hql) {

        return getSession().createQuery(hql);
    }

    public SQLQuery getSQLQuery(String sql) {
        return getSession().createSQLQuery(sql);
    }

    public Criteria getCriteria(DetachedCriteria detachedCriteria) {
        return detachedCriteria.getExecutableCriteria(getSession());
    }

    public Query getNamedQuery(String namedQuery) {
        try {
            return getSession().getNamedQuery(namedQuery);
        }catch (Exception e){
            return null;
        }
    }

    public SQLQuery getNamedSQLQuery(String namedSQLQuery) {
        return (SQLQuery) getSession().getNamedQuery(namedSQLQuery);
    }

    public void save(E entity) {
        getSession().save(entity);
    }

    public void update(E entity) {

        getSession().update(entity);

    }

    public void delete(E entity) {

        getSession().delete(entity);

    }

    public void merge(E entity) {

        getSession().merge(entity);

    }

    public E get(PK id) {
        return (E) getSession().get(type,id);
    }

    public List<?> list(String named, Map params, int firstResult, int maxResult, ResultTransformer resultTransformer) {
        Query query = getNamedQuery(named);
        log.debug(named+"++++++");
        if(query==null){
           query=getQuery(named);
        }
        if(params!=null) {
            query.setProperties(params);
        }
        if(firstResult!=0) {
            query.setFirstResult(firstResult);
        }
        if(maxResult!=0){
            query.setMaxResults(maxResult);
        }
        if(resultTransformer!=null) {
            query.setResultTransformer(resultTransformer);
        }
        query.setCacheable(true);
        return query.list();
    }

    public List<?> list(DetachedCriteria detachedCriteria, int firstResult, int maxResult, ResultTransformer resultTransformer) {
        Criteria criteria=getCriteria(detachedCriteria);
        if(firstResult!=0) {
            criteria.setFirstResult(firstResult);
        }
        if(maxResult!=0) {
            criteria.setMaxResults(maxResult);
        }
        if(resultTransformer!=null) {
            criteria.setResultTransformer(resultTransformer);
        }
        criteria.setCacheable(true);
        return criteria.list();
    }

    public void browse(Pagination pagination) {
        Object condition=pagination.getCondition();
        int firstResult=(pagination.getIndex()-1)*pagination.getSize();
        int maxResult=pagination.getSize();
        if(condition instanceof  Map){
            Map map= (Map) condition;
            ResultTransformer resultTransformer=null;
            if(map.get(Pagination.TRANSFORMER)!=null&&  map.get(Pagination.TRANSFORMER) instanceof ResultTransformer){
                resultTransformer= (ResultTransformer) map.get(Pagination.TRANSFORMER);
            }
            if(map.containsKey(Pagination.COUNT_DC)&&map.containsKey(Pagination.RESULT_DC)) {
                DetachedCriteria countdc = (DetachedCriteria) map.get(Pagination.COUNT_DC);
                pagination.setTotal(findCount(countdc));
                DetachedCriteria resultdc = (DetachedCriteria) map.get(Pagination.RESULT_DC);
                pagination.setResult(list(resultdc,firstResult,maxResult,resultTransformer));
            }else if(map.containsKey(Pagination.COUNT_HQL)&&map.containsKey(Pagination.RESULT_HQL)&&map.containsKey(Pagination.PARAMS)){
                String counthql= (String) map.get(Pagination.COUNT_HQL);
                String resulthql= (String) map.get(Pagination.RESULT_HQL);
                Map params= (Map) map.get(Pagination.PARAMS);
                pagination.setTotal(findCount(counthql,params));
                pagination.setResult(list(resulthql,params,firstResult,maxResult,resultTransformer));
            }else{
                throw new RuntimeException("查询条件不符合规范");
            }

        }else{
            throw new RuntimeException("查询条件不符合规范");
        }


    }

    public void batch(String named, Map params) {
        Query query = getNamedQuery(named);
        if(query==null){
            query=getQuery(named);
        }
        if(params!=null) {
            query.setProperties(params);
        }
        query.executeUpdate();


    }

    public E findOne(String hql, Map params) {
        Query query = getNamedQuery(hql);
        if(query==null){
            query=getQuery(hql);
        }
        if(params!=null) {
            query.setProperties(params);
        }
        //query.setResultTransformer(Transformers.aliasToBean(type));
        return (E) query.uniqueResult();
    }

    public E findOne(DetachedCriteria detachedCriteria) {
        Criteria criteria=getCriteria(detachedCriteria);
        //criteria.setResultTransformer(Transformers.aliasToBean(type));
        return (E) criteria.uniqueResult();
    }

    public int findCount(String named, Map params) {
        Query query = getNamedQuery(named);
        if(query==null){
            query=getQuery(named);
        }
        if(params!=null) {
            query.setProperties(params);
        }
        if(query.uniqueResult()!=null) {
            return ((Long) query.uniqueResult()).intValue();
        }
        return 0;
    }

    public int findCount(DetachedCriteria detachedCriteria) {
        Criteria criteria=getCriteria(detachedCriteria);
        return (Integer)criteria.uniqueResult();
    }
}